﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

// Qt headers
#include <QBrush>
#include <QFont>
#include <QFontMetrics>

//gcmp headers
#include "GcmpModel.h"
#include "JournalUtils.h"

// custom headers
#include "EditingParametersTableModel.h"
#include "EditingParametersTableSymbols.h"
#include "IParameter.gcs.h"
#include "IParameterDefinition.gcs.h"


#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 
namespace gmepgcs 
{
    EdittingParametersTableModel::EdittingParametersTableModel(QObject *parent) :
        QAbstractTableModel(parent),
        m_mpIsValid()
    {
    }

    EdittingParametersTableModel::~EdittingParametersTableModel()
    {
    }

    int EdittingParametersTableModel::rowCount(const QModelIndex & parent) const
    {
        if (parent.isValid())
        {
            return 0;
        }
        
        return (int)m_vParameters.size();
    }

    int EdittingParametersTableModel::columnCount(const QModelIndex & parent) const
    {
        Q_UNUSED(parent);

        return COL_TOTAL_COUNT;
    }
    
    QVariant EdittingParametersTableModel::data(const QModelIndex & index, int role) const
    {
        if (!index.isValid())
        {
            return QVariant();
        }

        IParameter *pParameter = static_cast<IParameter*>(index.internalPointer());
        if (!pParameter || !pParameter->Definition)
        {
            return QVariant();
        }
        
        int col = index.column();
        QFont font;
        font.setFamily("Microsoft YaHei");
        font.setPixelSize(12);

        // 参数名
        if (col == COL_PARAMETER_NAME) 
        {
            const std::wstring& text = pParameter->Definition->GetName();

            switch (role) {
            case Qt::DisplayRole:
            case Qt::EditRole:
                return QString::fromStdWString(text);
            case Qt::TextAlignmentRole:
                return (int)Qt::AlignRight | Qt::AlignVCenter;
            case Qt::BackgroundColorRole:
                return pParameter->IsNameEditable() 
                    ? QBrush(QColor(255, 255, 255, 255), Qt::BrushStyle::SolidPattern)
                    : QBrush(QColor(245, 245, 245, 255), Qt::BrushStyle::SolidPattern);
            case Qt::FontRole:
                return font;
            case Qt::ForegroundRole:
                return QColor(120, 122, 131, 255);
            case Qt::SizeHintRole:
            {
                if (text.length() > 10) // 两行
                {
                    return QSize(144, 8 + QFontMetrics(font).height()*2 + 8);
                }
                else
                    break;
            }
            case Qt::UserRole:
                return true;
            default:
                break;
            }
        }
        // 参数值
        else if (col == COL_PARAMETER_VALUE) 
        {
            switch (role) {
            case Qt::DisplayRole:
                return QString::fromStdWString(pParameter->GetDisplayValue());
            case Qt::EditRole:
                return QString::fromStdWString(pParameter->Value);
            case Qt::TextAlignmentRole:
                return (int)Qt::AlignLeft | Qt::AlignVCenter;
            case Qt::BackgroundColorRole:
                return pParameter->IsValueEditable()
                    ? QBrush(QColor(255, 255, 255, 255), Qt::BrushStyle::SolidPattern)
                    : QBrush(QColor(245, 245, 245, 255), Qt::BrushStyle::SolidPattern);
            case Qt::FontRole:
                return font;
            case Qt::ForegroundRole:
                return QColor(0, 40, 51, 255);
            default:
                break;
            }
        }
        // 单位
        else if (col == COL_PARAMETER_UNIT)
        {
            switch (role) {
            case Qt::DisplayRole:
            case Qt::EditRole:
                return QString::fromStdWString(pParameter->Definition->GetUnitSymbol());
            case Qt::TextAlignmentRole:
                return (int)Qt::AlignLeft | Qt::AlignVCenter;
            case Qt::BackgroundColorRole:
                return pParameter->IsUnitEditable()
                    ? QBrush(QColor(255, 255, 255, 255), Qt::BrushStyle::SolidPattern)
                    : QBrush(QColor(245, 245, 245, 255), Qt::BrushStyle::SolidPattern);
            case Qt::FontRole:
                return font;
            case Qt::ForegroundRole:
                return QColor(0, 40, 51, 255);                
            default:
                break;
            }
        }
        // 实例标记
        else if (col == COL_PARAMETER_INSTANCE_MARK) 
        {
            switch (role) {
            case Qt::DisplayRole:
            case Qt::EditRole:
                return pParameter->Definition->GetIsInstance();
            case Qt::SizeHintRole:
                return QSize(12, 12);
            case Qt::DecorationRole:
            {
                if (pParameter->Definition->GetIsInstance() && pParameter->IsInstanceEditable())
                {
                    return QString::fromStdWString(L":/images/icon_tick_ffffff_12.png");
                }

                if (pParameter->Definition->GetIsInstance() && !(pParameter->IsInstanceEditable()))
                {
                    return QString::fromStdWString(L":/images/icon_tick_ffffff_12.png");
                }

                if (!(pParameter->Definition->GetIsInstance()))
                {
                    return QString();
                }
            }
            case Qt::TextAlignmentRole:
                return (int)Qt::AlignHCenter | Qt::AlignVCenter;
            case Qt::BackgroundColorRole:
                return pParameter->IsInstanceEditable()
                    ? QBrush(QColor(255, 255, 255, 255), Qt::BrushStyle::SolidPattern)
                    : QBrush(QColor(245, 245, 245, 255), Qt::BrushStyle::SolidPattern);
            case Qt::ForegroundRole:
            {
                if (pParameter->Definition->GetIsInstance())
                {
                    return pParameter->IsInstanceEditable()
                        ? QColor(82, 145, 221, 255)
                        : QColor(89, 99, 112, 255);
                }
                else
                {
                    return pParameter->IsInstanceEditable()
                        ? QColor(255, 255, 255, 255)
                        : QColor(240, 240, 245, 255);
                }
            }
            default:
                break;
            }
        }

        return QVariant();
    }

    QVariant EdittingParametersTableModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
        switch (orientation) 
        {
        // 水平 headers
        case Qt::Horizontal:
        {
            QBrush background(QColor(217, 221, 228, 255), Qt::BrushStyle::SolidPattern);
            QFont font;
            font.setFamily("Microsoft YaHei");
            font.setPixelSize(12);
            QColor foreground(40, 40, 51, 255);
            switch (section)
            {                
            case COL_PARAMETER_NAME:// 参数名
                switch (role)
                {
                case Qt::DisplayRole:
                    return QString::fromStdWString(GBMP_TR(L"属性"));
                case Qt::TextAlignmentRole:
                    return (int)Qt::AlignRight | Qt::AlignVCenter;
                case Qt::BackgroundColorRole:
                    return background;
                case Qt::FontRole:
                    return font;
                case Qt::ForegroundRole:
                    return foreground;
                case Qt::AccessibleDescriptionRole:
                    return QString::fromStdWString(GBMP_TR(L"属性"));
                default:
                    break;
                }                
            case COL_PARAMETER_VALUE:// 参数值
                switch (role)
                {
                case Qt::DisplayRole:
                    return QString::fromStdWString(GBMP_TR(L"值"));
                case Qt::TextAlignmentRole:
                    return (int)Qt::AlignLeft | Qt::AlignVCenter;
                case Qt::BackgroundColorRole:
                    return background;
                case Qt::FontRole:
                    return font;
                case Qt::ForegroundRole:
                    return foreground;
                case Qt::AccessibleDescriptionRole:
                    return QString::fromStdWString(GBMP_TR(L"值"));
                default:
                    break;
                }
            case COL_PARAMETER_UNIT:// 单位                
                switch (role)
                {
                case Qt::DisplayRole:
                    return QString::fromStdWString(GBMP_TR(L"单位"));
                case Qt::TextAlignmentRole:
                    return (int)Qt::AlignLeft | Qt::AlignVCenter;
                case Qt::BackgroundColorRole:
                    return background;
                case Qt::FontRole:
                    return font;
                case Qt::ForegroundRole:
                    return foreground;
                case Qt::AccessibleDescriptionRole:
                    return QString::fromStdWString(GBMP_TR(L"单位"));
                default:
                    break;
                }
            case COL_PARAMETER_INSTANCE_MARK:// 实例标记
                switch (role)
                {
                case Qt::DisplayRole:
                    return QString::fromStdWString(GBMP_TR(L"实例"));
                case Qt::TextAlignmentRole:
                    return (int)Qt::AlignHCenter | Qt::AlignVCenter;
                case Qt::BackgroundColorRole:
                    return background;
                case Qt::FontRole:
                    return font;
                case Qt::ForegroundRole:
                    return foreground;
                case Qt::AccessibleDescriptionRole:
                    return QString::fromStdWString(GBMP_TR(L"实例"));
                default:
                    break;
                }
            default:
                break;
            }
            break;
        }

        // 垂直 headers
        case Qt::Vertical:
        {
            if (role == Qt::AccessibleDescriptionRole)
            {
                IParameter *parameter = static_cast<IParameter*>(index(section, COL_PARAMETER_NAME).internalPointer());
                if (parameter && parameter->Definition)
                {
                    return QString::fromStdWString(L"Name: %1").arg(QString::fromStdWString(parameter->Definition->GetName()));
                }
                return QString::fromStdWString(L"ROW_%1").arg(section);
            }
            break;
        }

        default:
            break;
        }

        return QVariant();
    }

    QModelIndex EdittingParametersTableModel::index(int row, int column, const QModelIndex & parent) const
    {
        if (QAbstractItemModel::hasIndex(row, column, parent) &&
            row >=0 && row < m_vParameters.size() &&
            column>=0 && column < columnCount()
            )
        {
            auto parameter = m_vParameters.at(row).get();
            return QAbstractItemModel::createIndex(row, column, parameter);
        }

        return QAbstractTableModel::index(row, column, parent);
    }

    Qt::ItemFlags EdittingParametersTableModel::flags(const QModelIndex & index) const
    {
        if (!index.isValid())
        {
            return QAbstractTableModel::flags(index);
        }

        IParameter *parameter = static_cast<IParameter *>(index.internalPointer());
        if (!parameter)
        {
            return QAbstractTableModel::flags(index);
        }
        
        int32_t col = index.column();
        if (col == COL_PARAMETER_NAME && parameter->IsNameEditable())
        {
            return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
        }
        if (col == COL_PARAMETER_VALUE && parameter->IsValueEditable())
        {
            return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
        }
        if (col == COL_PARAMETER_UNIT && parameter->IsUnitEditable())
        {
            return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
        }
        if (col == COL_PARAMETER_INSTANCE_MARK && parameter->IsInstanceEditable())
        {
            return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
        }

        return QAbstractTableModel::flags(index);
    }

    bool EdittingParametersTableModel::setData(const QModelIndex & index, const QVariant & value, int role)
    {
        if (gcmp::JournalUtils::IsInReplay())
        {
            return SetReplayParameter(index, value, role);
        }

        if (!index.isValid())
        {
            return false;
        }

        IParameter *parameter = static_cast<IParameter *>(index.internalPointer());
        if (!parameter)
        {
            return false;
        }

        int32_t col = index.column();

        if (col == COL_PARAMETER_VALUE)
        {
            switch (role)
            {
            case Qt::EditRole:
            {
                if (!parameter->Definition)
                {
                    return false;
                }

                auto newValue = value.toString().trimmed().toStdWString();
                if (parameter->Value == newValue)
                {
                    return false;
                }

                emit ModifyValueOfParameterRequired(parameter->Definition->GetName(), parameter->Value, newValue);
            }
            default:
                break;
            }
        }

        return false;
    }

    void EdittingParametersTableModel::SetParameters(std::vector<std::shared_ptr<IParameter>> paramters)
    {
        int oldRowCount = rowCount();
        if (oldRowCount > 0)
        {
            beginRemoveRows(QModelIndex(), 0, oldRowCount - 1);
            removeRows(0, oldRowCount);
            endRemoveRows();
        }

        m_vParameters = paramters;
        m_mpIsValid.clear();
        for (auto &param : m_vParameters)
        {
            if (param && param->Definition)
            {
                m_mpIsValid[param->Definition->GetId()] = true;
            }
        }

        int newRowCount = (int)m_vParameters.size();
        if (newRowCount > 0)
        {
            beginInsertRows(QModelIndex(), 0, newRowCount - 1);
            insertRows(0, newRowCount);
            endInsertRows();
        }

        emit dataChanged(index(0, 0), index(newRowCount - 1, columnCount() - 1));
    }

    bool EdittingParametersTableModel::SetReplayParameter(const QModelIndex & index, const QVariant & value, int role)
    {
        if (!index.isValid())
        {
            return false;
        }

        IParameter *parameter = static_cast<IParameter *>(index.internalPointer());
        if (!parameter)
        {
            return false;
        }

        int32_t col = index.column();

        if (col == COL_PARAMETER_VALUE)
        {
            switch (role)
            {
            case Qt::EditRole:
            case Qt::DisplayRole:
            {
                if (!parameter->Definition)
                {
                    return false;
                }

                auto newValue = value.toString().trimmed().toStdWString();
                if (parameter->Value == newValue)
                {
                    return false;
                }

                emit ModifyValueOfParameterRequired(parameter->Definition->GetName(), parameter->Value, newValue);
            }
            default:
                break;
            }
        }

        return false;
    }

    void EdittingParametersTableModel::UpdateParameterValue(const std::wstring & parameterName, const std::wstring & parameterOldValue, const std::wstring & parameterNewValue)
    {
        for (int i = 0; i != rowCount(); ++i)
        {
            auto currentIndex = index(i, COL_PARAMETER_VALUE);
            if (currentIndex.isValid())
            {
                IParameter *parameter = static_cast<IParameter *>(currentIndex.internalPointer());
                if (parameter && parameter->Definition && parameter->Definition->GetName() == parameterName)
                {
                    emit dataChanged(currentIndex, currentIndex, { Qt::EditRole | Qt::DisplayRole });
                    break;
                }
            }
        }
    }
}
